package pl.edu.agh.ki.neuralnetwork.layer;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import pl.edu.agh.ki.neuralnetwork.exceptions.NeuronAlreadyConnectedException;
import pl.edu.agh.ki.neuralnetwork.exceptions.NeuronNotConnectedException;
import pl.edu.agh.ki.neuralnetwork.exceptions.WrongArgException;
import pl.edu.agh.ki.neuralnetwork.neurons.InnerNeuron;
import pl.edu.agh.ki.neuralnetwork.neurons.KohonenNeuron;
import pl.edu.agh.ki.neuralnetwork.neurons.Neuron;

public class KohonenLayer implements Layer<InnerNeuron> {
	KohonenNeuron[][] neuronTab;
	private final int cols;
	private final int rows;
	int currentIndex = 0;
	private final int inputSize;
	private int neighbourhood;
	private int neighbourhoodRadius;

	public KohonenLayer(int rows, int cols,int inputSize,int neighbourhood, int neighbourhoodRadius) {
		this.rows = rows;
		this.cols = cols;
		this.inputSize = inputSize;
		this.neighbourhood = neighbourhood;
		this.neighbourhoodRadius = neighbourhoodRadius;
		neuronTab = new KohonenNeuron[rows][cols];
	}

	public KohonenNeuron get(int i) {
		return neuronTab[i / cols][i % cols];
	}

	public int size() {
		return rows * cols;
	}

	public Iterator<InnerNeuron> iterator() {
		return new Iterator<InnerNeuron>() {
			private int counter = 0;
			public boolean hasNext() {
				return counter<rows*cols;
			}

			public InnerNeuron next() {
				return get(counter++);
			}

			public void remove() {
				// TODO Auto-generated method stub
			}
		};
	}

	public void add(InnerNeuron neuron) {
		//System.out.println(currentIndex+" "+currentIndex / cols+" "+currentIndex % cols);
		neuronTab[currentIndex / cols][currentIndex % cols] = (KohonenNeuron) neuron;
		neuronTab[currentIndex / cols][currentIndex % cols].setXY(currentIndex / cols,currentIndex % cols);
		currentIndex++;
	}

	public List<Neuron> getNeuronsList() {
		List<Neuron> neuronsList = new ArrayList<Neuron>(rows * cols);
		for (int i = 0; i < rows; i++)
			for (int j = 0; j < cols; j++)
				neuronsList.add(neuronTab[i][j]);
		return neuronsList;
	}




	public void setNeighbourHood() {
		//for all neurons in layer
		for (int r = 0; r < rows; r++) {
			for (int c = 0; c < cols; c++) {
				
				if(neighbourhood==0){
					neuronTab[r][c].addNeighBour(neuronTab[r][c]);
				}else{
					//check if any could be his neighbour
					for (int y = 0; y < rows; y++) {
						for (int x = 0; x < cols; x++) {
							if(neighbourhood==1){
								if( ((x-c)*(x-c) + (y-r)*(y-r))<neighbourhoodRadius*neighbourhoodRadius ){
									neuronTab[r][c].addNeighBour(neuronTab[y][x]);
								}
							}else if(neighbourhood==2){
								if( ((x-c)*(x-c) + (y-r)*(y-r))<=neighbourhoodRadius*neighbourhoodRadius ){
									neuronTab[r][c].addNeighBour(neuronTab[y][x]);
								}
							}
						}
					}
				}
				
			}
		}
	}
	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		for (int i = 0; i < rows; i++) {
			for (int j = 0; j < cols; j++) {
				sb.append(neuronTab[i][j]);
				
			}
			sb.append("-------\n");
		}
		return sb.toString();
	}

}
